/*
 * Fichier: ExercisePane.java
 * Crée le: 15 septembre 2007.
 * Modifié: 15 février 2009.
 * Auteurs: Sébastien ESTIENNE.
 * SiteWeb: http://www.prog-info.org/
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.OF
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
package javaexos.tools;

import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.JOptionPane;

import javaexos.model.ExerciseModel;

/**
 * <p>Exécute la démo d'un exercice.</p>
 */
public class ExerciseLauncher
{
   /** Logger. */
   private static final Logger LOGGER = Log.getInstance().getLogger(
         "javaexos.tools.ExerciseLauncher");
   
   /** L'exercice exécuté. */
   private ExerciseModel exercise;
   
   /** Le texte de sortie standard. */
   private String output;
   
   /** Le texte de sortie d'erreur. */
   private String error;
   
   
   /**
    * <p>Constructeur.</p>
    * @param exercise L'exercice exécuté.
    */
   public ExerciseLauncher(ExerciseModel exercise)
   {
      this.exercise = exercise;
   }
   
   
   /**
    * <p>Exécute l'exercice.</p>
    * @return true si la commande a été exécutée avec succès, sinon false.
    */
   public boolean execute()
   {
      // Le processus.
      Process proc;
      
      try
      {
         if(this.exercise.getType().equals(ExerciseModel.ExoType.APPLET))
         {
            // Exécution de la commande.
            proc = Runtime.getRuntime().exec("appletviewer \"" + getClass().getResource("/" 
                  + Constants.CHAPTERS_NAME.replace("?", String.valueOf(
                        this.exercise.getChapter().getNumber())) 
                  + "/" + this.exercise.getMainClass() + ".html") + "\"");
         }
         else
         {
            // Exécution de la commande.
            proc = Runtime.getRuntime().exec("java -classpath \"" 
                  + System.getProperty("java.class.path") + "\" " 
                  + Constants.CHAPTERS_NAME.replace("?", String.valueOf(
                        this.exercise.getChapter().getNumber())) 
                  + "." + this.exercise.getMainClass());
         }
         
         // Récupération des flux de sortie.
         readOutputStream(proc.getInputStream());
         readErrorStream(proc.getErrorStream());
      }
      catch(IOException e)
      {
         LOGGER.log(Level.SEVERE, e.getMessage());
         
         // Application appletviewer non disponible.
         if(e.getMessage().contains("appletviewer"))
         {
            JOptionPane.showMessageDialog(null, "Application appletwiewer non disponible!", 
                  "appletviewer", JOptionPane.INFORMATION_MESSAGE);
         }
      }
      
      return (this.error == null || this.error.isEmpty());
   }
   
   
   /**
    * <p>Lecture du flux sur la sortie standard.</p>
    * @param input Le flux à lire.
    * @throws IOException Si une erreur d'entrée / sortie se produit.
    */
   private void readOutputStream(InputStream input) throws IOException
   {
      StringBuilder msg = new StringBuilder();
      int c;

      // Lecture du flux.
      while((c = input.read()) != -1)
      {
         msg.append((char) c);
      }

      // Enregistrement de la sortie.
      this.output = msg.toString();
   }
   
   
   /**
    * <p>Lecture du flux sur la sortie d'erreur.</p>
    * @param input Le flux à lire.
    * @throws IOException Si une erreur d'entrée / sortie se produit.
    */
   private void readErrorStream(InputStream input) throws IOException
   {
      StringBuilder msg = new StringBuilder();
      int c;

      // Lecture du flux.
      while((c = input.read()) != -1)
      {
         msg.append((char) c);
      }

      // Enregistrement de l'erreur.
      this.error = msg.toString();

      // Log de l'erreur.
      if(msg.length() > 0)
      {
         LOGGER.log(Level.SEVERE, msg.toString());
      }
   }
   
   
   /**
    * <p>Retourne le texte de sortie standard.</p>
    * @return Renvoie le texte la sortie standard.
    */
   public String getOutput()
   {
      return this.output;
   }
   
   
   /**
    * <p>Retourne le texte de sortie d'erreur.</p>
    * @return Renvoie le texte de sortie d'erreur.
    */
   public String getError()
   {
      return this.error;
   }
}
